/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package proy1sistdistribuidos.modelo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import proy1sistdistribuidos.control.advertisements.AdvertisementImagenImpl;
import proy1sistdistribuidos.control.advertisements.MyAdvertisementRecurso;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @author Carlos Diaz Maya, Juan Felipe Garcia
 */
public class ControladorEstado {
    private String estadoLocal;
    public static String ESTADOABIERTO = "ABIERTO";
    public static String ESTADOCERRADO = "CERRADO";
    public static String RUTAFISICA = "./RepositorioImagenes/EstadoGlobal";

    private EstadoGeneral estadoGeneralInicial;
    private TreeMap<String, EstadoGeneral> estadoGlobalDescarga;
    private ArrayList<NodoRemoto> listaNodos;
    private static ControladorEstado instancia;
    private Integer identificador;
    
    
    private ControladorEstado() {
        this.estadoLocal = ControladorEstado.ESTADOABIERTO;
        estadoGlobalDescarga = new TreeMap<String, EstadoGeneral>();
        estadoGeneralInicial  = new EstadoGeneral();
        listaNodos = new ArrayList<NodoRemoto>();
        //TODO: Falta que lea estado del HDD
    }

    public static ControladorEstado obtenerInstancia() {
        if(instancia == null){
            instancia = new ControladorEstado();
        }
        return instancia;
    }

    public void actualizarEstadoGeneralInicial(EstadoGeneral estado) throws Exception{
        this.estadoGeneralInicial = estado;

        EstructuraDatosEstado est = new EstructuraDatosEstado(estadoGeneralInicial, estadoGlobalDescarga);
        est.persistirEstructura(RUTAFISICA);

        this.notificarActualizacionEstadoAOtrosNodos(est);



    }

    public void notificarActualizacionEstadoAOtrosNodos(EstructuraDatosEstado est) {
        List<NodoRemoto> recs = listaNodos;
        if (recs != null) {
            for (NodoRemoto rec : recs) {
                try {
                    String ip = rec.getDireccionIP();
                    Socket elSockete = new Socket(ip, ControladorExclusion.puertoSocketes);

                    String cadenaXML = est.aString(); //Se serializa el estado global de la maquina a XML

                    BASE64Encoder codifBase64 = new BASE64Encoder();
                    String cadenaXMLBase64 = codifBase64.encode(cadenaXML.getBytes());
                    cadenaXMLBase64 = cadenaXMLBase64.replaceAll("\r\n", "_CHARRO2_");
                    cadenaXMLBase64 = cadenaXMLBase64.replaceAll("\n", "_CHARRO_");
                    String comando = "RecibirEstadoGlobal_"+cadenaXMLBase64;
                    PrintWriter pregunta = new PrintWriter(elSockete.getOutputStream(), true);
                    BufferedReader respuesta = new BufferedReader(new InputStreamReader(elSockete.getInputStream()));



                    //Se envia el comando al nodo
                    pregunta.println(comando);

                    //Se recibe la respuesta del nodo
                    String respNodo = respuesta.readLine();


                    if (respNodo != null && !respNodo.equals("")) {
                        //Se recibe el Estado Global codificado en Base64
                        BASE64Decoder decodeBase64 = new BASE64Decoder();
                        String respNodoProce = respNodo.replaceAll("_CHARRO2_", "\r\n");
                        respNodoProce = respNodoProce.replaceAll("_CHARRO_", "\n");
                        byte[] cadenaXMLEstadoRecibidoBytes = decodeBase64.decodeBuffer(respNodoProce);
                        String cadenaXMLEstadoRecibido = new String(cadenaXMLEstadoRecibidoBytes);
                        EstructuraDatosEstado estructMaquinaRemota = new EstructuraDatosEstado(cadenaXMLEstadoRecibido);
                        EstadoGeneral estadoMaquinaRemota = estructMaquinaRemota.getEstadoGeneralInicial();
                        est.getEstadoGlobalDescarga().put(rec.getDireccionIP(), estadoMaquinaRemota);
                        
                    }

                    elSockete.close();
                } catch (UnknownHostException ex) {
                    ex.printStackTrace();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }

            }
        }
    }

    public Integer obtenerConsecutivoEstado(Integer incremento){
        if(this.identificador == null){
            this.identificador = 0;
        }
        this.identificador+=incremento;
        
        return this.identificador;

    }




    public String getEstadoLocal() {
        return this.estadoLocal;
    }

    public void setEstadoLocal(String estadoLocal) {
        this.estadoLocal = estadoLocal;
        //TODO: FALTA QUE GUARDE A HDD
    }

    public TreeMap<String, EstadoGeneral> getEstadoGlobalDescarga() {
        return estadoGlobalDescarga;
    }

    public void setEstadoGlobalDescarga(TreeMap<String, EstadoGeneral> estadoGlobalDescarga) {
        this.estadoGlobalDescarga = estadoGlobalDescarga;
    }

    public EstadoGeneral getEstadoLocalDescarga() {
        return estadoGeneralInicial;
    }

    public void setEstadoLocalDescarga(EstadoGeneral estadoLocalDescarga) {
        this.estadoGeneralInicial = estadoLocalDescarga;
    }

    /**
     * @return the listaNodos
     */
    public ArrayList<NodoRemoto> getListaNodos() {
        return listaNodos;
    }

    /**
     * @param listaNodos the listaNodos to set
     */
    public void setListaNodos(ArrayList<NodoRemoto> listaNodos) {
        this.listaNodos = listaNodos;
    }
}
